﻿using Roton.Memory;
using Roton.ZZT;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Roton.Wrapper.ZZT
{
    class SuperZZTMemoryWrapper : MemoryWrapper
    {
        public SuperZZTMemoryWrapper()
        {
            this.heap = new Heap();
            this.segment = new Segment(0xE730);

            this.elementOffset = 0x7CAA;
            this.elementSize = 0x00C2;
            this.thingOffset = 0x6AB5;
            this.thingSize = 0x0019;

            this.segment.Write(0x0000, Properties.Resources.szztextra);
            this.segment.Write(this.elementOffset, Properties.Resources.szztelement);

            this.boardProperties = new BoardWrapperProperties();
            this.boardProperties.Width = 96 + 2;
            this.boardProperties.Height = 80 + 2;
            this.boardProperties.OffsetName = 0x2BAE;
            this.boardProperties.OffsetTiles = 0x2BEB;
            this.boardProperties.OffsetMaxShots = 0x7767;
            this.boardProperties.OffsetDark = int.MinValue; // not in SZZT
            this.boardProperties.OffsetExits = 0x7768;
            this.boardProperties.OffsetRestartZap = 0x776C;
            this.boardProperties.OffsetEnter = 0x776D;
            this.boardProperties.OffsetCamera = 0x776F;
            this.boardProperties.OffsetTimeLimit = 0x7773;

            this.elementProperties = new ElementWrapperProperties();
            this.elementProperties.OffsetChar = 0x0000;
            this.elementProperties.OffsetColor = 0x0001;
            this.elementProperties.OffsetDestructible = 0x0002;
            this.elementProperties.OffsetPushable = 0x0003;
            this.elementProperties.OffsetEditorFloor = 0x0004;
            this.elementProperties.OffsetFloor = 0x0005;
            this.elementProperties.OffsetDrawCodeEnable = 0x0006;
            this.elementProperties.OffsetCycle = 0x000B;
            this.elementProperties.OffsetMenu = 0x0015;
            this.elementProperties.OffsetKey = 0x0017;
            this.elementProperties.OffsetName = 0x0018;
            this.elementProperties.OffsetEditorCategory = 0x002D;
            this.elementProperties.OffsetEditorP1 = 0x0042;
            this.elementProperties.OffsetEditorP2 = 0x0057;
            this.elementProperties.OffsetEditorP3 = 0x006C;
            this.elementProperties.OffsetEditorBoard = 0x0081;
            this.elementProperties.OffsetEditorStep = 0x0096;
            this.elementProperties.OffsetEditorCode = 0x00AB;
            this.elementProperties.OffsetPoints = 0x00C0;

            this.stateProperties = new StateWrapperProperties();
            this.stateProperties.OffsetAboutShown = int.MinValue; // not in SZZT
            this.stateProperties.OffsetActIndex = 0xB95A;
            this.stateProperties.OffsetAlertAmmo = 0x7C0B;
            this.stateProperties.OffsetAlertDark = int.MinValue; // not in SZZT
            this.stateProperties.OffsetAlertEnergy = 0x7C11;
            this.stateProperties.OffsetAlertFake = 0x7C0F;
            this.stateProperties.OffsetAlertForest = 0x7C0E;
            this.stateProperties.OffsetAlertGem = 0x7C10;
            this.stateProperties.OffsetAlertNoAmmo = 0x7C0C;
            this.stateProperties.OffsetAlertNoShoot = 0x7C0D;
            this.stateProperties.OffsetAlertNotDark = int.MinValue; // not in SZZT
            this.stateProperties.OffsetAlertNoTorch = int.MinValue; // not in SZZT
            this.stateProperties.OffsetAlertTorch = int.MinValue; // not in SZZT
            this.stateProperties.OffsetBoardCount = 0x7784;
            this.stateProperties.OffsetBorderTile = int.MinValue; // not in SZZT
            this.stateProperties.OffsetBreakGameLoop = 0x7C9E;
            this.stateProperties.OffsetCancelScroll = 0x0000;
            this.stateProperties.OffsetDefaultBoardName = 0x2B32;
            this.stateProperties.OffsetDefaultSaveName = 0x2AF4;
            this.stateProperties.OffsetDefaultWorldName = 0x2B70;
            this.stateProperties.OffsetEdgeTile = 0x2260;
            this.stateProperties.OffsetEditorMode = 0xB960;
			// forest sound index = 0x2334
            this.stateProperties.OffsetGameCycle = 0xB958;
            this.stateProperties.OffsetGameOver = 0xCD9B;
            this.stateProperties.OffsetGamePaused = 0xB95C;
            this.stateProperties.OffsetGameQuiet = 0xCD9A;
            this.stateProperties.OffsetGameSpeed = 0x7CA4;
            this.stateProperties.OffsetGameWaitTime = 0xB956;
            this.stateProperties.OffsetInit = 0x0000;
            this.stateProperties.OffsetKeyArrow = 0xCC84;
            this.stateProperties.OffsetKeyPressed = 0xCC76;
            this.stateProperties.OffsetKeyShift = 0xCC72;
            this.stateProperties.OffsetKeyVector = 0xCC6E;
            this.stateProperties.OffsetLineChars = 0x22BA;
            this.stateProperties.OffsetMessage = 0x7C22; //message2 = 0x7C60
            this.stateProperties.OffsetOOPByte = 0xB962;
            this.stateProperties.OffsetOOPNumber = 0xB97A;
            this.stateProperties.OffsetOOPWord = 0xB964;
            this.stateProperties.OffsetPlayerElement = 0x7CA0;
            this.stateProperties.OffsetQuitZZT = 0x7C9D;
            this.stateProperties.OffsetSoundBuffer = 0xCF9E;
            this.stateProperties.OffsetSoundPlaying = 0xD0A8;
            this.stateProperties.OffsetSoundPriority = 0xCD9C;
            this.stateProperties.OffsetSoundTicks = 0xCF9D;
            this.stateProperties.OffsetStarChars = 0x2064;
            this.stateProperties.OffsetStartBoard = 0x7CA2;
            this.stateProperties.OffsetThingCount = 0x6AB3;
            this.stateProperties.OffsetTransporterHChars = 0x1F64;
            this.stateProperties.OffsetTransporterVChars = 0x1E64;
            this.stateProperties.OffsetVector4 = 0x2250;
            this.stateProperties.OffsetVector8 = 0x2230;
            this.stateProperties.OffsetVisibleTileCount = int.MinValue;
            this.stateProperties.OffsetWebChars = 0x227C;
            this.stateProperties.OffsetWorldFileName = 0x2AB6;
            this.stateProperties.OffsetWorldLoaded = 0xB97C;

            this.thingProperties = new ThingWrapperProperties();
            this.thingProperties.OffsetX = 0x0000;
            this.thingProperties.OffsetY = 0x0001;
            this.thingProperties.OffsetStepX = 0x0002;
            this.thingProperties.OffsetStepY = 0x0004;
            this.thingProperties.OffsetCycle = 0x0006;
            this.thingProperties.OffsetP1 = 0x0008;
            this.thingProperties.OffsetP2 = 0x0009;
            this.thingProperties.OffsetP3 = 0x000A;
            this.thingProperties.OffsetFollower = 0x000B;
            this.thingProperties.OffsetLeader = 0x000D;
            this.thingProperties.OffsetUnderID = 0x000F;
            this.thingProperties.OffsetUnderColor = 0x0010;
            this.thingProperties.OffsetPointer = 0x0011;
            this.thingProperties.OffsetInstruction = 0x0015;
            this.thingProperties.OffsetLength = 0x0017;

            this.worldProperties = new WorldWrapperProperties();
            this.worldProperties.LengthFlags = 0x0014;
            this.worldProperties.OffsetAmmo = 0x784C;
            this.worldProperties.OffsetGems = 0x784E;
            this.worldProperties.OffsetKeys = 0x7850;
            this.worldProperties.OffsetHealth = 0x7857;
            this.worldProperties.OffsetBoard = 0x7859;
            this.worldProperties.OffsetTorches = int.MinValue; // not in SZZT
            this.worldProperties.OffsetTorchCycles = int.MinValue; // not in SZZT
            this.worldProperties.OffsetEnergyCycles = 0x785D;
            this.worldProperties.OffsetScore = 0x7861;
            this.worldProperties.OffsetFlags = 0x7863;
            this.worldProperties.OffsetTimePassed = 0x79C8;
            this.worldProperties.OffsetLocked = 0x79CC;
            this.worldProperties.OffsetStones = 0x79CD;

            this.board = new BoardWrapper(0, segment, boardProperties);
            this.state = new StateWrapper(0, segment, stateProperties);
            this.world = new WorldWrapper(0, segment, worldProperties);

            this.elementTypeList = new ElementType[]
            {
                ElementType.Empty,
                ElementType.BoardEdge,
                ElementType.Messenger,
                ElementType.Monitor,
                ElementType.Player,
                ElementType.Ammo,
                ElementType.None,
                ElementType.Gem,
                ElementType.Key,
                ElementType.Door,
                ElementType.Scroll,
                ElementType.Passage,
                ElementType.Duplicator,
                ElementType.Bomb,
                ElementType.Energizer,
                ElementType.None,
                ElementType.Clockwise,
                ElementType.Counter,
                ElementType.None,
                ElementType.Water, //lava
                ElementType.Forest,
                ElementType.Solid,
                ElementType.Normal,
                ElementType.Breakable,
                ElementType.Boulder,
                ElementType.SliderNS,
                ElementType.SliderEW,
                ElementType.Fake,
                ElementType.Invisible,
                ElementType.BlinkWall,
                ElementType.Transporter,
                ElementType.Line,
                ElementType.Ricochet,
                ElementType.None,
                ElementType.Bear,
                ElementType.Ruffian,
                ElementType.Object,
                ElementType.Slime,
                ElementType.None,
                ElementType.SpinningGun,
                ElementType.Pusher,
                ElementType.Lion,
                ElementType.Tiger,
                ElementType.None,
                ElementType.Head,
                ElementType.Segment,
                ElementType.None,
                ElementType.Floor,
                ElementType.WaterN,
                ElementType.WaterS,
                ElementType.WaterW,
                ElementType.WaterE,
                ElementType.None,
                ElementType.None,
                ElementType.None,
                ElementType.None,
                ElementType.None,
                ElementType.None,
                ElementType.None,
                ElementType.Roton,
                ElementType.DragonPup,
                ElementType.Pairer,
                ElementType.Spider,
                ElementType.Web,
                ElementType.Stone,
                ElementType.None,
                ElementType.None,
                ElementType.None,
                ElementType.None,
                ElementType.Bullet,
                ElementType.BlinkRayH,
                ElementType.BlinkRayV,
                ElementType.Star,
                ElementType.BlueText,
                ElementType.GreenText,
                ElementType.CyanText,
                ElementType.RedText,
                ElementType.PurpleText,
                ElementType.BrownText,
                ElementType.BlackText
            };

            this.elementActCode = new ActDelegate[]
            {
                Act.Null,
                Act.Null,
                Act.Messenger,
                Act.Monitor,
                Act.Player,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Scroll,
                Act.Null,
                Act.Duplicator,
                Act.Bomb,
                Act.Null,
                Act.Null,
                Act.Clockwise,
                Act.Counter,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.BlinkWall,
                Act.Transporter,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Bear,
                Act.Ruffian,
                Act.Object,
                Act.Slime,
                Act.Null,
                Act.SpinningGun,
                Act.Pusher,
                Act.Lion,
                Act.Tiger,
                Act.Null,
                Act.Head,
                Act.Segment,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Roton,
                Act.DragonPup,
                Act.Pairer,
                Act.Spider,
                Act.Null,
                Act.Stone,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Bullet,
                Act.Null,
                Act.Null,
                Act.Star,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null
            };

            this.elementDrawCode = new DrawDelegate[]
            {
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Duplicator,
                Draw.Bomb,
                Draw.Null,
                Draw.Null,
                Draw.Clockwise,
                Draw.Counter,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.BlinkWall,
                Draw.Transporter,
                Draw.Line,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Object,
                Draw.Null,
                Draw.Null,
                Draw.SpinningGun,
                Draw.Pusher,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.DragonPup,
                Draw.Null,
                Draw.Null,
                Draw.Web,
                Draw.Stone,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Star,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null
            };

            this.elementInteractCode = new InteractDelegate[]
            {
                Interact.Null,
                Interact.BoardEdge,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Ammo,
                Interact.Null,
                Interact.Gem,
                Interact.Key,
                Interact.Door,
                Interact.Scroll,
                Interact.Passage,
                Interact.Null,
                Interact.Bomb,
                Interact.Energizer,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Water, //lava
                Interact.Forest,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.PushableGeneric,
                Interact.PushableGeneric,
                Interact.PushableGeneric,
                Interact.Fake,
                Interact.Invisible,
                Interact.Null,
                Interact.Transporter,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.EnemyGeneric,
                Interact.EnemyGeneric,
                Interact.Object,
                Interact.Slime,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.EnemyGeneric,
                Interact.EnemyGeneric,
                Interact.Null,
                Interact.EnemyGeneric,
                Interact.EnemyGeneric,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.EnemyGeneric,
                Interact.EnemyGeneric,
                Interact.EnemyGeneric,
                Interact.EnemyGeneric,
                Interact.Null,
                Interact.Stone,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.EnemyGeneric,
                Interact.Null,
                Interact.Null,
                Interact.EnemyGeneric,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null
            };

        }
    }
}
